Lightkurve quicklook prototype¶
This version of the notebook is trying to incorporate short cadence data into the same widget by limiting the range of values plotted at one time.
In [1]:
%matplotlib notebook
from lightkurve import KeplerTargetPixelFile
import numpy as np
Let’s make the Jupyter cells wider
In [2]:
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))
Download a Kepler target pixel file (TPF)¶
In [3]:
#tpf = KeplerTargetPixelFile.from_archive('210698281', campaign=13)
tpf = KeplerTargetPixelFile.from_archive('249914869', campaign=15, cadence='short')
tpf.flux.shape
Downloading URL https://mast.stsci.edu/api/v0/download/file?uri=mast:K2/url/missions/k2/target_pixel_files/c15/249900000/14000/ktwo249914869-c15_spd-targ.fits.gz to ./mastDownload/K2/ktwo249914869-c15_sc/ktwo249914869-c15_spd-targ.fits.gz ... [Done]
Out[3]:
(127288, 9, 10)
Define a new interact routine including pixel selection for the mask¶
In [4]:
def interact(tpf, rmin=None, rmax=None, lc=None):
"""
Interact with a linked target pixel file and lightcurve
Parameters
----------
rmin : an optional minimum time index for initial light curve. Defaults to 0 if not supplied by user.
rmax : an optional maximum time index for initial light curve. Defaults to 3000 if not supplied by user. Note that
rmax - rmin should not be more than ~10,000 for quicker plotting
lc : an optional user-supplied pre-processed lightcurve for this target
Returns
-------
ax : matplotlib.axes._subplots.AxesSubplot
The matplotlib axes object.
"""
lc = tpf.to_lightcurve()
try:
from ipywidgets import interact
import ipywidgets as widgets
from bokeh.io import push_notebook, show, output_notebook
from bokeh.plotting import figure, ColumnDataSource
from bokeh.models import Span
from bokeh.models import LogColorMapper
from bokeh.layouts import row, column
from bokeh.themes import Theme
from bokeh.models.tools import HoverTool, PointDrawTool
from bokeh.models.widgets import Button
output_notebook()
except ImportError:
raise ImportError('The quicklook tool requires Bokeh and ipywidgets. See the Installation Guide.')
if lc is None:
lc = tpf.to_lightcurve()
if rmin is None:
rmin = 0
if rmax is None:
rmax = 3000
source = ColumnDataSource(data=dict(
time=lc.time, flux=lc.flux,
cadence=lc.cadenceno,
quality=lc.quality))
def update(f, v, r):
vert.update(location=tpf.time[f])
s2_dat.data_source.data['image'] = [tpf.flux[f,:,:]]
s2_dat.glyph.color_mapper.high = v[1]
s2_dat.glyph.color_mapper.low = v[0]
steps.data_source.data.update(time=lc.time[r[0]:r[1]],
flux=lc.flux[r[0]:r[1]],
cadence=lc.cadenceno[r[0]:r[1]],
quality=lc.quality[r[0]:r[1]])
push_notebook()
title = "Quicklook lightcurve for {} target {}".format(tpf.mission, tpf.keplerid)
p = figure(title=title, plot_height=300, plot_width=600, tools="tap,pan,wheel_zoom,box_zoom,reset")#, theme=theme)
p.yaxis.axis_label = 'Normalized Flux'
p.xaxis.axis_label = 'Time - 2454833 (days)'
steps = p.step('time', 'flux', line_width=1, color='gray', source=source, nonselection_line_color='gray')
#p.step(cuttime, cutflux, line_width=1, color='gray', source=source, nonselection_line_color='gray')
r = p.circle('time', 'flux', source=source, fill_alpha=0.3, size=8,line_color=None,
#r = p.circle(cuttime, cutflux, source=source, fill_alpha=0.3, size=8,line_color=None,
selection_color="firebrick", nonselection_fill_alpha=0.0,
nonselection_fill_color="grey",nonselection_line_color=None,
nonselection_line_alpha=0.0, fill_color=None,
hover_fill_color="firebrick",hover_alpha=0.9,hover_line_color="white")
p.add_tools(HoverTool(tooltips=[("index", "$index"),
("cadence", "@cadence"),
("time", "@time{0,0.000}"),
("flux", "@flux"),
("quality", "@quality")],
renderers=[r], mode='mouse', point_policy="snap_to_data"))
vert = Span(location=800, dimension='height', line_color='firebrick', line_width=4, line_alpha=0.5)
p.add_layout(vert)
s2 = figure(plot_width=300, plot_height=300, title='Target Pixel File', tools='tap, box_zoom, reset')
s2.yaxis.axis_label = 'Pixel Row Number'
s2.xaxis.axis_label = 'Pixel Column Number'
pedestal = np.nanmin(tpf.flux)
vlo, lo, med, hi, vhi = np.fix(np.nanpercentile(tpf.flux-pedestal, [0.2, 1, 50, 95, 99.8]))
color_mapper = LogColorMapper(palette="Viridis256", low=lo, high=hi)
s2_dat = s2.image([pedestal+tpf.flux[0,:,:]], x=tpf.column, y=tpf.row,
dw=tpf.shape[2], dh=tpf.shape[1], dilate=True,
color_mapper=color_mapper)
source2 = ColumnDataSource(data=dict(xx=x_vals+0.5, yy=y_vals+0.5))
r1 = s2.rect('xx', 'yy', 1, 1, source=source2, fill_color='gray', fill_alpha=0.4, line_color='white')
ptool = PointDrawTool(renderers=[r1])
s2.add_tools(ptool)
s2.toolbar.active_tap = ptool
#button = Button(label="Foo", button_type="success")
#def my_button_handler(new):
# print('Button option ' + str(new) + ' selected.')
#button.on_click(my_button_handler)
show(row(p, s2), notebook_handle=True)
n_cad, nx, ny = tpf.flux.shape
play = widgets.Play(
interval=10,
value=9,
min=0,
max=n_cad-1,
step=1,
description="Press play",
disabled=False)
#wbutton = widgets.Button(
# description='Click me',
# disabled=False,
# button_style='', # 'success', 'info', 'warning', 'danger' or ''
# icon='check')
#def on_button_clicked(b):
# bool_mask = tpf.pipeline_mask*False
# for xi, yi in zip(r1.data_source.data['xx'], r1.data_source.data['yy']):
# xc = np.int(np.round(xi-0.5)-tpf.column)
# yc = np.int(np.round(yi-0.5)-tpf.row)
# bool_mask[xc, yc] = True
# print(xc, yc)
# source.data['flux'] = tpf.to_lightcurve(aperture_mask=bool_mask).flux
# print('click', bool_mask.sum())
#wbutton.on_click(on_button_clicked)
style = {'description_width': 'initial'}
f_slider = widgets.IntSlider(min=0,max=n_cad-1,step=1,value=5,
layout=widgets.Layout(width='40%', height='20px'),
description="Pixel file plotted:", style=style)
r_slider = widgets.IntRangeSlider(value=[rmin,rmax], min=0,max=n_cad-1,step=1,
layout=widgets.Layout(width='80%', height='20px'),
description="Light curve range:", style=style)
vstep = np.round((hi-lo)/300.0, 1)
v_slider = widgets.FloatRangeSlider(value=[lo, hi],
min=0,
max=hi,
step=vstep,
description='v:',
continuous_update=False,
layout=widgets.Layout(width='30%', height='20px'))
widgets.jslink((play, 'value'), (f_slider, 'value'))
ui = widgets.VBox([widgets.HBox([r_slider]),widgets.HBox([play, f_slider, v_slider])])
out = widgets.interactive_output(update, {'f': f_slider, 'v':v_slider, 'r':r_slider})
display(ui, out)
return p
Define where the pixels are for this particular target pixel file¶
In [5]:
xx=tpf.column + np.arange(tpf.shape[2])
yy=tpf.row + np.arange(tpf.shape[1])
In [6]:
x, y = np.meshgrid(xx, yy)
In [7]:
x_vals, y_vals = x[tpf.pipeline_mask], y[tpf.pipeline_mask]
Test the new interact tools¶
Delete pixel boxes by while clicking the box, then press ‘delete’ while your cursor is still hovering over the image.
In [8]:
out = interact(tpf)
In [ ]:
Below this is stuff for cleaning lightcurves…¶
In [ ]:
lc_sff = lc_cln.correct(restore_trend=True)
In [16]:
lc_cln = my_custom_lc_cleaner(tpf, cleaning='best')
In [15]:
def my_custom_lc_cleaner(tpf, cleaning='best'):
'''Returns a clean lightcurve given an input tpf'''
nan_mask = np.all(np.isnan(tpf.flux), axis=0)
empty_mask = tpf.pipeline_mask * False
aper_mask = empty_mask
aper_mask[1:-1, 1:-1] = True
back_mask = ~aper_mask & ~nan_mask
lc_aper = tpf.to_lightcurve(aperture_mask=aper_mask)/aper_mask.sum()
lc_back = tpf.to_lightcurve(aperture_mask=back_mask)/back_mask.sum()
lc_bg_sub = lc_aper - lc_back.flux
# Flag outliers
_, outliers1 = lc_aper.remove_outliers(return_mask=True)
_, outliers2 = lc_back.remove_outliers(return_mask=True)
_, outliers3 = lc_aper.flatten().remove_outliers(return_mask=True)
outlier_dict= {'none': outliers1*False,
'safe':(tpf.quality > 0.0),
'soft': outliers1,
'medium':(outliers1 | outliers2),
'best': (outliers1 | outliers2 | (tpf.quality > 0.0)),
'aggressive':(outliers1 | outliers2 | (tpf.quality > 0.0) | outliers3)}
outliers = outlier_dict[cleaning]
lc_cln = lc_bg_sub[~outliers]
return lc_cln
In [ ]:
lc_cln = my_custom_lc_cleaner(tpf, cleaning='best')
In [ ]:
In [ ]: